package com.coder.network.request

import okhttp3.MediaType
import okhttp3.RequestBody
import okio.*
import java.io.IOException

/**
 * @author yuhushuan
 * @ClassName: ProgressRequestBody
 * @Description: 封装带有进度的请求体
 * @date 17-1-25 11:22
 */
class ProgressRequestBody
/**
 * 构造函数，赋值
 *
 * @param requestBody
 * @param listener
 */(
        /**
         * 实际的待包装请求体
         */
        private val mRequestBody: RequestBody,
        /**
         * 进度回调接口
         */
        private val mListener: ProgressRequestListener?) : RequestBody() {
    /**
     * 包装完成的BufferedSink
     */
    private var mBufferedSink: BufferedSink? = null

    /**
     * @see .writeTo
     */
    private var isWriteLog = false
    override fun contentType(): MediaType? {
        return mRequestBody.contentType()
    }

    @Throws(IOException::class)
    override fun contentLength(): Long {
        return mRequestBody.contentLength()
    }

    /**
     * 如果OkHttpClient添加了HttpLoggingInterceptor(Level.BODY)则执行两次，第一次为打印日志，第二次为上传数据
     *
     * @param sink
     * @throws IOException
     */
    @Throws(IOException::class)
    override fun writeTo(sink: BufferedSink) {
        //包装
        mBufferedSink = Okio.buffer(sink(sink))
        //写入
        mRequestBody.writeTo(mBufferedSink)
        //必须调用flush，否则最后一部分数据可能不被写入
        mBufferedSink!!.flush()
        isWriteLog = false
    }

    private fun sink(sink: Sink): Sink {
        return object : ForwardingSink(sink) {
            //当前写入字节数
            var bytesWritten = 0L

            //总字节长度，避免多次调用contentLength()方法
            var contentLength = 0L
            @Throws(IOException::class)
            override fun write(source: Buffer, byteCount: Long) {
                super.write(source, byteCount)
                if (0L == contentLength) {
                    contentLength = contentLength()
                }
                bytesWritten += byteCount
                if (mListener != null && !isWriteLog) {
                    mListener.onRequestProgress(bytesWritten, contentLength, bytesWritten == contentLength)
                }
            }
        }
    }

    companion object {
        private const val tag = "ProgressRequestBody"
    }
}